import m3u8
import requests

from common_tool import common_Md5Str, common_ParseUrl, common_CacheRecode, common_DeleteAllCache, common_CacheTsPath, common_CacheM3u8FilePath, common_EncryKeyFilePath, common_AddMission, common_SetCommonCacheMission, common_SetCommonCacheMission, common_IsUrl


class DealM3U8File():
    def __init__(self, host: str, path: str) -> None:
        self._host = host
        self._path = path

    def downLoad(self, host: str, path: str) -> (m3u8.M3U8 | None, str | None, dict | None):
        try:
            url = f'https://{host}{path}'
            res = requests.get(url=url)
            play_list = m3u8.loads(content=res.text, uri=url)
            if play_list.is_variant:
                playlists = play_list.playlists
                if len(playlists) > 0:
                    sub_url = playlists[0].absolute_uri
                    host, path = common_ParseUrl(url=sub_url)
                    return self.downLoad(host=host, path=path)
                else:
                    return None, None, None
            else:
                return_key_info = None
                if len(play_list.keys) > 0:
                    key_info = play_list.keys[0]
                    if key_info is not None:
                        key_str = requests.get(url=key_info.absolute_uri).text
                        return_key_info = {
                            'key': key_str,
                            'iv': key_info.iv,
                            'method': key_info.method
                        }
                return play_list, res.text, return_key_info
        except Exception as e:
            return None, None, None

    def dealPlayList(self, play_list: m3u8.M3U8, md5_str: str, key_info: dict | None) -> dict:
        cache = common_CacheRecode(path=self._path)
        if cache is not None:
            cache_md5 = cache['md5']
            if cache_md5 == md5_str:
                return cache
            else:
                common_DeleteAllCache(path=self._path)

        if key_info is not None:
            key_path = common_EncryKeyFilePath(path=self._path)
            play_list.keys[0].uri = key_path
            with open(key_path, 'w', encoding='utf-8') as file:
                file.write(key_info['key'])

        segments = play_list.segments
        data = []
        for i in range(len(segments)):
            segment = segments[i]
            url = segment.uri
            if not common_IsUrl(input_str=url):
                url = f'{segment.base_uri}{url}'
            _, path = common_ParseUrl(url)
            ts_path = common_CacheTsPath(path=path)
            data.append(
                {
                    'location': i,
                    'url': url,
                    'file_path': ts_path,
                    'is_done': False
                }
            )
            segment.uri = ts_path
        m3u8_path = common_CacheM3u8FilePath(path=path)
        with open(m3u8_path, 'w', encoding='utf-8') as file:
            content = play_list.dumps()
            content = content.replace("\\", '/')
            file.write(content)

        return_data = {
            'm3u8_path': m3u8_path,
            'md5': md5_str,
            'decry_info': key_info,
            'data': data
        }
        return return_data

    def startMission(self) -> bool:

        play_list, res_content, key_info = self.downLoad(
            host=self._host, path=self._path)
        if play_list is None:
            return False

        # MD5比较
        will_md5_str = res_content
        if key_info is not None:
            will_md5_str = will_md5_str + key_info['key']

        md5_str = common_Md5Str(content=will_md5_str)

        common_cache_mission = self.dealPlayList(play_list=play_list,
                                                 md5_str=md5_str, key_info=key_info)

        common_SetCommonCacheMission(
            common_cache_mission=common_cache_mission)

        mission_datas = common_cache_mission['data']
        for mission_data in mission_datas:
            if mission_data['is_done'] == False:
                common_AddMission(mission=mission_data)

        return True
